/**************************************************************
 * common.c - 
 * Copyright (c) 2009  Qin Xiaoxue  <crs.chin@gmail.com>
 *
 * This file is  free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
**************************************************************/


#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>

#include "common.h"


gboolean quiet = FALSE;
gboolean verbose = FALSE;
gboolean printerr = TRUE;
gboolean printbug = TRUE;

void print_verb(const gchar *fmt, ...)
{
  va_list ap;

  if(! verbose || quiet || ! fmt)
	return;

  va_start(ap, fmt);
  printf("[INFO]: ");
  vprintf(fmt, ap);
  va_end(ap);
}


void print_info(const gchar *fmt, ...)
{
  va_list ap;

  if( quiet || ! fmt)
	return;

  va_start(ap, fmt);
  printf("[INFO]: ");
  vprintf(fmt, ap);
  va_end(ap);
}


void print_warn(const gchar *fmt, ...)
{
  va_list ap;

  if(! printerr || ! fmt)
	return;

  va_start(ap, fmt);
  fprintf(stderr, "[WARN]: ");
  vfprintf(stderr, fmt, ap);
  va_end(ap);
}


void print_err(const gchar *fmt, ...)
{
  va_list ap;

  if(! printerr || ! fmt)
	return;

  va_start(ap, fmt);
  fprintf(stderr, "[*ERROR*]: ");
  vfprintf(stderr, fmt, ap);
  va_end(ap);
}


void print_bug(const gchar *fmt, ...)
{
  va_list ap;

  if(! printbug || ! fmt)
	return;

  va_start(ap, fmt);
  fprintf(stderr, "[*BUG*]: ");
  vfprintf(stderr, fmt, ap);
  va_end(ap);
}


void *checked_malloc(size_t size)
{
  void *p=malloc(size);
  if(!p) {
	print_err("can not alloc memory!!!abortting...\n");
    exit (-1);
  }
  memset(p,0,size);
  return p;
}

void *checked_realloc(void *p, size_t size)
{
  void *ret = realloc(p, size);
  if(! ret) {
    write(STDERR_FILENO, "** OOM!\n", 8);
    exit(-1);
  }
  return ret;
}


size_t secure_fread(void *buf, size_t size, size_t nmem, FILE *fstream)
{
  size_t readin = 0;

  do{
    readin += fread(buf + size * readin, size, nmem - readin, fstream);
    if(readin == nmem)
      break;
  }while(! feof(fstream));

  return readin;
}


size_t secure_fwrite(void *buf, size_t size, size_t nmem, FILE *fstream)
{
  size_t writeout = 0;

  do{
    writeout += fwrite(buf + size * writeout, size, nmem - writeout, fstream);
    if(writeout == nmem)
      break;
  }while(! ferror(fstream));

  return writeout;
}


gboolean  file_cat(FILE *from, FILE *to)
{
  gchar buf[2048];
  gint i, j, size;

  if(! from || ! to)
    return FALSE;

  rewind(from);

  do{
    size = fread(buf, 1, 2048, from);
    if(size)  {
      i = 0;
      while(size)  {
	j = fwrite(buf + i, 1, size, to);
	size -= j;
	i += j;
      }
    }
  }while(! feof(from));

  return TRUE;
}


gboolean  file_copy(FILE *from, FILE *to)
{
  gchar buf[2048];
  gint i, j, size;

  if(! from || ! to)
    return FALSE;

  rewind(from);

  if(ftruncate(fileno(to), 0))  {
    perror("** ftruncate");
    return FALSE;
  }

  do{
    size = fread(buf, 1, 2048, from);
    if(size)  {
      i = 0;
      while(size)  {
	j = fwrite(buf + i, 1, size, to);
	size -= j;
	i += j;
      }
    }
  }while(! feof(from));

  return TRUE;
}


/*********************** guess title from file name************/

int isalldigit(const char *str)
{
  while(*str)
    if(! isdigit(*str++))
      return FALSE;

  return TRUE;
}


char *unescape(const char *str)
{
  char *buf, *p;
  int x;

  if(! str)
    return NULL;

  buf = (char *)checked_malloc(strlen(str) + 1);
  p = buf;

  while(*str) {
    if(*str != '%') {
      *p++ = *str++;
      continue;
    }

    str++;
    if(sscanf(str,"%2x",&x)) {
      *p++ = x;
      str += 2;
      continue;
    }

    *p++ = *str++;
  }
  *p = '\0';

  return buf;
}


/*
 * if @outquote is true, count @c only out quotes, blank it if there
 * is any unballenced quote.
 */
static int count_char(char *str, char c, int outquote)
{
  int inquote = 0, i = 0;
  char *p;

  if(! str)
    return 0;

  while(*str) {
    if(outquote)
      if(*str == '\"') {
	p = str + 1;
	while(*p && *p++ != '\"');
	if(! *p)
	  *str = ' ';
	else
	  str = p + 1;
      }
    if(*str++ == c)
      i++;
  }

  return i;
}


static int word_len(const char *str)
{
  int i = 0;

  while(! isspace(*str++))
    i++;

  return i;
}


char *translate(char *str, const char *from, const char *to)
{
  int offset, len;
  char *orig = str;

  len = strlen(from);
  while(*str) {
    for(offset = 0; offset < len; offset++)
      if(*str == *(from + offset)) {
	*str = *(to + offset);
	break;
      }
    str++;
  }
  return orig;
} 


/* static char *impact(char *str) */
/* { */
/*   char *p = str; */
/*   char *tmp; */
/*   int itmp; */

/*   if(! p) */
/*     return NULL; */

/*   if(isspace(*p) || *p == '-' || *p == '_') { */
/*     for(tmp = p+1; isspace(*tmp) && *tmp; tmp++); */
/*     if(! *tmp) { */
/*       *p = '\0'; */
/*       while(*(--p) == '-' || *p == '_')  *p = '\0'; */
/*       return str; */
/*     } */
/*     itmp = word_len(tmp); */
/*     memmove(p, tmp, itmp); */
/*     p += itmp; */
/*   } */


/*   while(*p) { */
/*     if(isspace(*p)) { */
/*       *p = ' '; */
/*       for(tmp = p+1; isspace(*tmp) && *tmp; tmp++); */
/*       if(! *tmp) { */
/* 	*p = '\0'; */
/* 	break; */
/*       } */

/*       if(tmp > p+1) { */
/* 	itmp = word_len(tmp); */
/* 	memmove(p+1, tmp, itmp); */
/* 	p += itmp + 1; */
/* 	//	continue; */
/*       } */
/*     } */
/*     if((*p == '-' || *p == '_')  &&  */
/*        (*(p+1) == '_' || *(p+1) == '-')) */
/*       *(p+1) = ' '; */
      
/*     p++; */
/*   } */

/*   while(*(--p) == '-' || *p == '_')  *p = '\0'; */
/*   return str; */
/* } */

static int isdelim(char ch, char *delim)
{
    while(*delim)
      if(*delim++ == ch)
	return TRUE;
    return FALSE;
}


char *impact(char *str, char *delim, int hunger)
{
  int indelim = FALSE;
  int inspace = FALSE;
  char *s = str, *tmp , *head;

  tmp = (char *)checked_malloc(strlen(str) + 1);
  head = tmp;
  while((isspace(*s)  || isdelim(*s, delim)) && *s != '\0') s++;

  while(*s) {
    if(isdelim(*s, delim))
      if(! indelim) {
	*tmp++ = *s++;
	indelim = TRUE;
	inspace = FALSE;
      }else
	s++;

    if(! *s)  break;

    if(isspace(*s)) {
      if(! indelim)
	inspace = TRUE;
      s++;
      continue;
    }

    if(inspace)
      if(! hunger)
	*tmp++ = ' ';
    *tmp++ = *s++;
    indelim = FALSE;
    inspace = FALSE;
  }

  *tmp = '\0';
  strcpy(str, head);
  free(head);

  return str;
}


char *guess_filename(const char *str, char **artist)
{
  char *fname, *path, *unescap, *tmp = NULL;
  char *seperator;
  char *seq[3] = { NULL, NULL, NULL};
  int cnt[4] = { 0, '-', 0, '_' };
  int *maxcnt, i = 0;

  *artist = NULL;

  if(! str) {
    *artist = NULL;
    return NULL;
  }

  path = strdup(str);
  if(strchr(path, '%')) {
    unescap = unescape(path);
    fname = basename(unescap);
  } else
    fname = basename(path);


  fname = translate(fname, "[].(){}", "__     ");
  fname = impact(fname, "-_", TRUE);

  printf("-- %s\n",fname);

  cnt[0] = count_char(fname, cnt[1], TRUE);
  cnt[2] = count_char(fname, cnt[3], TRUE);

  maxcnt = cnt[0] > cnt[2] ? &cnt[0] : &cnt[2];

  tmp = fname;
  while(i < (*maxcnt > 2 ? 2 : *maxcnt + 1)) {
    seperator = strchr(tmp, *(maxcnt+1));
    seq[i] = (char *)checked_malloc((seperator ? seperator - tmp : strlen(tmp)) + 1);
    strncpy(seq[i], tmp, (seperator ? seperator - tmp : strlen(tmp)));
    seq[i][(seperator ? seperator - tmp : strlen(tmp))] = '\0';
    tmp = seperator + 1;
    i++;
  }

  if(unescap)  free(unescap);
  free(path);


  if(seq[0]) {
    if(isalldigit(seq[0])) {
      if(! seq[1])
	return seq[0];
      if(seq[2])
	*artist = seq[2];
      free(seq[0]);
      return seq[1];
    }else {
      if(seq[2])   
	free(seq[2]);
      if(seq[1])
	*artist = seq[1];
      return seq[0];
    }
  }

  return NULL;
}


char *strip(char *str,int onlyends)
{
  int i,j,k;
  char *t;
  int isbegin;

  isbegin=1;
  i=strlen(str);
  t=(char *)malloc(i+1);
  if(!t) {
    fprintf(stderr,"**running out of memory or a bug encoutered!\n"
	    "cleanning up...");
    exit (FALSE);
  }
  for(j=0,k=0;j<i;j++) {
    if(isbegin && 
       ( str[j] == ' ' ||
	 isspace(str[j]) ) )
      {
	j++;
	continue;
      }

    isbegin=0;

    if(!onlyends &&
       ( str[j] == ' ' ||
	 isspace(str[j]) ) &&
       ( str[j+1] == ' ' ||
	 isspace(str[j+1]) ) )
      {
	j++;
	continue;
      }
    if(isspace(str[j]))  {  /* removing carrige return from dos text file*/
      t[k++]=' ';
      continue;
    }
    t[k++]=str[j];
  }
  t[k]='\0';
  strcpy(str,t);
  free(t);
  return str;
}
